<template>
  <MyDialog
    v-model="confirmDialogVisible"
    title="用户承诺须知"
    width="420px"
    :modal="true"
    :close-on-click-modal="false"
    confirmText="我已知晓，同意"
    @confirm="handleConfirm"
    @cancel="handleCancel"
  >
    <div style="font-weight:bold;margin-bottom:8px;color:#222;">本声明将帮助您更好地在本平台上传和管理您的作品。您若上传作品，即视为您以充分知悉并充分接受以下内容：</div>
    <ul style="font-size:14px;line-height:1.7;color:#222;">
      <li>您作为使用者在本平台上传、发布的作品，应具有独立、完整的知识产权，不得侵犯他人知识产权等任何权利。</li>
      <li>您在使用本平台上传、发布作品时，应当自觉遵守国家法律法规、社会公德、尊重社会公德、社会公序良俗等。</li>
      <li>如因上传、发布作品而引发的任何法律责任，由您自行承担。</li>
      <li>若您上传的作品/作品中素材（包括但不限于创意、文案、肖像、图片、音频、视频等）侵犯了任何第三方权利，本平台有权依权利人投诉或权利机关的要求对您的作品或账号采取处理措施。</li>
    </ul>
  </MyDialog>
  <MyDialog
      append-to-body
      v-model="showUploadDialog"
      title="素材上传"
      width="50%"
      :modal="true"
      :close-on-click-modal="false"
      @confirm="handleUploadConfirm"
  >
    <SourceAudioNew ref="sourceAudioNewRef" @confirm="handleUploadConfirm"/>
  </MyDialog>
  <div class="bg">
    <div class="container">
      <!-- 上区域 -->
      <div class="header">
        <div class="header-content">
          <div>
            <div class="section-title">个人声音克隆(0)</div>
            <el-card class="voice-clone-card">
              <div class="voice-clone-flex">
                <div class="voice-clone-info">
                  <div class="voice-clone-title">声音克隆</div>
                  <div class="voice-clone-desc">上传音频，打造专属个人声音模型</div>
                </div>
                <el-button type="primary" class="clone-btn" @click="drawerVisible = true">快速克隆</el-button>
              </div>
            </el-card>
            <el-row :gutter="20" style="margin-top: 20px;">
              <el-col :span="8" v-for="(item, idx) in contentListSelf" :key="item.id || idx" class="voice-col">
                <el-card class="voice-card">
                  <div class="voice-card-content">
                    <el-icon class="play-icon" @click="playAudio(item.demo_url)">
                      <VideoPause v-if="playingUrl === item.demo_url" />
                      <VideoPlay v-else />
                    </el-icon>
                    <span>{{ item.name }}</span>
                    <span v-if="item.demo_url" style="color:#409eff;cursor:pointer;margin-left:10px;" @click.stop="editSelfVoice(item)">修改</span>
                    <span v-else>克隆中</span>
                  </div>
                </el-card>
              </el-col>
            </el-row>
          </div>
        </div>
      </div>
      <!-- 下区域 -->
      <div class="main">
        <div class="section-title">声音库({{ contentList.length }})</div>
        <el-row :gutter="20">
          <el-col :span="8" v-for="(item, idx) in contentList" :key="item.id || idx" class="voice-col">
            <el-card class="voice-card">
              <div class="voice-card-content">
                <el-icon class="play-icon" @click="playAudio(item.url)">
                  <VideoPause v-if="playingUrl === item.url" />
                  <VideoPlay v-else />
                </el-icon>
                <span>{{ item.name }}</span>
              </div>
            </el-card>
          </el-col>
        </el-row>
      </div>
    </div>
  </div>
  <el-drawer
    v-model="drawerVisible"
    title="声音克隆"
    :with-header="true"
    size="600px"
    append-to-body
  >
    <div class="drawer-content">
      <h3>声音克隆流程</h3>
      <ol>
        <li>
          <b>上传参考音频</b>
          <div class="drawer-desc">
            上传一段音频用于克隆声音。音频的质量会直接影响到最后克隆声音的效果，因此请您尽量保证用于克隆的音频符合以下要求：<br>
            （1）音频时长：建议音频时长限制在10s-120s；<br>
            （2）音频质量：<br>
            a. 只有一个在说话，避免音频中出现多个人的声音；<br>
            b. 保证低底噪。说话人说话越清晰，最终克隆效果越好，音频底噪会严重影响克隆效果；<br>
            c. 保持音量大小、语速稳定、注意断句、避免口腔噪音(如口水声)、杂音、混响等情况；<br>
            d. 音频中不要有桌椅响声、键盘鼠标敲击声、衣服摩擦声等人为噪声；<br>
            e. 音频中可以存在口误。口误时无需终止录音,可停顿1~2秒后,继续录制即可。<br>
            （3）音频内容：<br>
            在录制音频前建议先确定好声音风格，在录音时尽量去贴近风格，避免录制的音频情绪韵律趋于平淡。如果希望克隆出的声音情绪饱满、韵律有起伏，请尽量上传表现力强的音频来克隆。<br>
            （4）音频格式：<br>
            支持mp3、m4a、wav文件格式，音频文件大小不超过20M。
          </div>
        </li>
        <li style="margin-top: 12px;">
          <b>预览效果</b>
          <div class="drawer-desc">
            音频上传后，请先预览试听声音效果。<br>
            如果对声音效果不满意，您可重新上传新的音频进行效果试听。<br>
            建议您保证音频符合上述要求，避免浪费修改编辑的次数。
          </div>
        </li>
        <li style="margin-top: 12px;">
          <b>积分消耗</b>
          <div class="drawer-desc">
            一经购买，概不退货。
          </div>
        </li>
      </ol>
    </div>
    <template #footer>
      <el-button type="primary" @click="handleNextStep">下一步</el-button>
    </template>
  </el-drawer>
  <el-drawer
    v-model="cloneDrawerVisible"
    title="声音克隆"
    :with-header="true"
    size="600px"
    append-to-body
    @close="handleCloneDrawerClose"
  >
    <div style="padding: 24px 0 0 0;">
      <div style="margin-bottom: 18px;">
        <div style="font-weight: bold; margin-bottom: 8px;">声音名称</div>
        <el-input placeholder="请输入声音名称" style="width: 100%;" v-model="voiceName"/>
      </div>
      <div style="margin-bottom: 18px;">
        <div style="font-weight: bold; margin-bottom: 8px;">参考音频</div>
        <el-card style="background: #fafbfc; border-radius: 8px;">
          <div style="display: flex; align-items: center; justify-content: space-between;">
            <div style="font-size: 14px; color: #333;">音频要求</div>
            <div style="font-size: 13px; color: #666;">文件格式: mp3、m4a、wav&nbsp;&nbsp;&nbsp;音频时长: 5秒~3分钟&nbsp;&nbsp;&nbsp;音频大小: 小于20MB</div>
          </div>
        </el-card>
      </div>
      <div style="margin-bottom: 32px;">
        <template v-if="!selectVideoData">
          <div
            style="width: 100%; border: 2px dashed #00b4ff; border-radius: 8px; padding: 40px 0; text-align: center; cursor: pointer; background: #fff;"
            @click="handleUploadClick"
          >
            <i class="el-icon-upload" style="font-size: 48px; color: #00b4ff; margin-bottom: 8px;"></i>
            <div style="font-size: 16px; color: #333;">请上传一段音频，用于声音克隆</div>
            <div style="font-size: 13px; color: #aaa;">点击此区域上传</div>
          </div>
        </template>
        <template v-else>
          <el-card
            style="display: flex; align-items: center; padding: 16px 20px; cursor: pointer; min-height: 60px;"
            @click="handleUploadClick"
            body-style="padding: 0;"
          >
            <div style="display: flex; align-items: center; width: 100%;">
              <!-- 左侧播放按钮 -->
              <div style="margin-right: 18px; display: flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 50%; background: #f5f7fa; cursor: pointer;" @click.stop="togglePlayAudio">
                <el-icon class="play-icon" style="font-size: 32px; color: #409eff;">
                  <VideoPause v-if="playingUrl === selectVideoData.url" />
                  <VideoPlay v-else />
                </el-icon>
              </div>
              <!-- 右侧内容 -->
              <div style="flex: 1; display: flex; flex-direction: column; justify-content: center;">
                <!-- 标题 -->
                <div style="font-size: 16px; font-weight: bold; color: #333; margin-bottom: 8px;">{{ selectVideoData.title }}</div>
                <!-- 进度条、时长、音量 -->
                <div style="display: flex; align-items: center; gap: 12px;">
                  <!-- 进度条 -->
                  <input type="range" min="0" :max="audioDuration" step="0.01" v-model="audioCurrentTime" @input="onSeekAudio" @click.stop style="flex: 1; height: 4px; accent-color: #409eff;" />
                  <!-- 当前时长/总时长 -->
                  <span style="font-size: 12px; color: #888; min-width: 70px; text-align: right;">{{ formatTime(audioCurrentTime) }} / {{ formatTime(audioDuration) }}</span>
                  <!-- 音量 -->
                  <input type="range" min="0" max="1" step="0.01" v-model="audioVolume" @input="onVolumeChange" @click.stop style="width: 60px; height: 4px; accent-color: #409eff; margin-left: 8px;" />
                </div>
              </div>
            </div>
          </el-card>
        </template>
      </div>
    </div>
    <template #footer>
      <el-button type="primary" @click="showCloneConfirmDialog = true">开始克隆</el-button>
    </template>
  </el-drawer>
  <MyDialog
    v-model="showCloneConfirmDialog"
    title="提示"
    width="360px"
    :modal="true"
    :close-on-click-modal="false"
    confirmText="确定"
    cancelText="取消"
    @confirm="handleCloneConfirm"
    @cancel="handleCloneCancel"
  >
    <div style="font-size: 16px; color: #222;">此步骤确认将会产生扣点</div>
  </MyDialog>
  <audio ref="audioRef" style="display:none" />
  <el-drawer
    v-model="editDrawerVisible"
    title="声音克隆"
    :with-header="true"
    size="600px"
    append-to-body
  >
    <div style="padding: 24px 0 0 0;">
      <div style="margin-bottom: 18px;">
        <div style="font-weight: bold; margin-bottom: 8px;">声音名称</div>
        <el-input :model-value="editItem?.name" disabled placeholder="声音名称" style="width: 100%;" />
      </div>
      <div style="margin-bottom: 18px;">
        <div style="font-weight: bold; margin-bottom: 8px;">参考音频</div>
        <el-card style="background: #fafbfc; border-radius: 8px;">
          <audio v-if="editItem?.url" :src="editItem.url" controls style="width: 100%;" />
        </el-card>
      </div>
      <div style="margin-bottom: 18px;">
        <div style="font-weight: bold; margin-bottom: 8px;">效果预览</div>
        <el-card style="background: #fafbfc; border-radius: 8px;">
          <audio v-if="editItem?.demo_url" :src="editItem.demo_url" controls style="width: 100%;" />
        </el-card>
      </div>
    </div>
    <template #footer>
      <el-button type="primary" @click="handleReclone">重新克隆</el-button>
    </template>
  </el-drawer>
</template>

<script setup lang="ts">
import {onMounted, ref, watch} from 'vue'
import axiosUtil from '../../axios-util/axios-util'
import { ElRow, ElCol, ElCard, ElButton, ElIcon, ElDrawer } from 'element-plus'
import { VideoPlay, VideoPause } from '@element-plus/icons-vue'
import SourceAudioNew from '../videoWarehouse/SourceAudioNew.vue'
import SourcePersonNew from '../videoWarehouse/SourcePersonNew.vue'
import MyDialog from "../common/MyDialog.vue";
 import { ElMessage, ElMessageBox } from 'element-plus'
import utils from '../../utils/utils'

//主题控制light  dark
const theme = utils.getTheme();
const drawerVisible = ref(false)
const confirmDialogVisible = ref(false)
const cloneDrawerVisible = ref(false)
const contentList = ref([])
const audioRef = ref<HTMLAudioElement | null>(null)
const playingUrl = ref('')
const showUploadDialog = ref(false)
const audioCurrentTime = ref(0)
const audioDuration = ref(0)
const audioVolume = ref(1)
const voiceName = ref("")
const showCloneConfirmDialog = ref(false)
const editDrawerVisible = ref(false)
const editItem = ref<any>(null)

const initContentList = async () => {
  const response = await axiosUtil.post('api/digitalpeople/voicelistkl', {})
  if (response.data.code === 1 && response.data.data) {
    contentList.value = response.data.data.gyvoice
    contentListSelf.value = response.data.data.klvoice
  }
}

const handleNextStep = () => {
  confirmDialogVisible.value = true
}

const handleConfirm = () => {
  confirmDialogVisible.value = false
  drawerVisible.value = false
  cloneDrawerVisible.value = true
}

const handleCancel = () => {
  confirmDialogVisible.value = false
}

const playAudio = (url: string) => {
  if (audioRef.value) {
    if (playingUrl.value === url && !audioRef.value.paused) {
      audioRef.value.pause()
      playingUrl.value = ''
      return
    }
    audioRef.value.src = url
    audioRef.value.play()
    playingUrl.value = url
  }
}

const sourceAudioNewRef = ref();
const selectVideoData = ref(null)

const handleUploadClick = () => {
  showUploadDialog.value = true
}

const handleUploadConfirm = () => {
  if (sourceAudioNewRef.value && sourceAudioNewRef.value.getSelectMateriaAll) {
    selectVideoData.value = sourceAudioNewRef.value.getSelectMateriaAll();
  }
  console.log(selectVideoData.value)
  showUploadDialog.value = false;
}

const togglePlayAudio = () => {
  if (!audioRef.value) return;
  if (playingUrl.value === selectVideoData.value.url && !audioRef.value.paused) {
    audioRef.value.pause();
    playingUrl.value = '';
  } else {
    audioRef.value.src = selectVideoData.value.url;
    audioRef.value.play();
    playingUrl.value = selectVideoData.value.url;
  }
}

const onSeekAudio = (e) => {
  if (audioRef.value) {
    audioRef.value.currentTime = Number(audioCurrentTime.value);
  }
}

const onVolumeChange = (e) => {
  if (audioRef.value) {
    audioRef.value.volume = Number(audioVolume.value);
  }
}

const formatTime = (val) => {
  const s = Math.floor(val);
  const m = Math.floor(s / 60);
  const ss = s % 60;
  return `${m.toString().padStart(2, '0')}:${ss.toString().padStart(2, '0')}`;
}

const handleCloneDrawerClose = () => {
  selectVideoData.value = null;
  if (audioRef.value) {
    audioRef.value.pause();
    playingUrl.value = '';
  }
}

const handleCloneConfirm = async() => {
  showCloneConfirmDialog.value = false;
  if(!voiceName.value){
    ElMessage.error('请输入声音名称')
  }
  if(!selectVideoData.value){
    ElMessage.error('请上传一段音频')
  }
  const response = await axiosUtil.post('api/megatts/addfyvoice', {
    "name": voiceName.value,
    "url": selectVideoData.value.url
  })
  if(response.data.code === 1){
    ElMessage.success(response.data.msg);
    // 定时器相关变量
    let timerId = null;
    const poll = async () => {
      const responseInit = await axiosUtil.post('api/digitalpeople/voicelistkl', {})
      if (responseInit.data.code === 1 && responseInit.data.data) {
        contentList.value = responseInit.data.data.gyvoice
        contentListSelf.value = responseInit.data.data.klvoice
        let shouldStop = false;
        responseInit.data.data.klvoice.forEach(element => {
          if(element.status !== '克隆中' && element.demo_url){
            shouldStop = true;
          }
        });
        if (shouldStop && timerId) {
          clearInterval(timerId);
          timerId = null;
        }
      }
    }
    // 立即执行一次
    poll();
    // 启动定时器
    timerId = setInterval(poll, 15000);
  }else {
    ElMessage.error(response.data.msg);
  }
}

const handleCloneCancel = () => {
  showCloneConfirmDialog.value = false;
}

const contentListSelf = ref([])

const editSelfVoice = (item) => {
  editItem.value = item;
  editDrawerVisible.value = true;
}

const handleReclone = () => {
  ElMessageBox.alert(
    '“重新克隆”可以上传新的音频进行克隆，您还有9次”重上传音频，打造专属个人快速克隆测试新克隆”的机会。<br><span style="color: red;">机会用完后，您无法再重新克隆，只参考音频声音模型能使用最后一次的克隆结果来完成克隆。</span>',
    '提示',
    {
      confirmButtonText: '已确认，重新克隆',
      type: 'warning',
      dangerouslyUseHTMLString: true,
      callback: () => {
        editDrawerVisible.value = false;
        cloneDrawerVisible.value = true;
      }
    }
  );
}

onMounted(() => {
  initContentList()
  if (audioRef.value) {
    audioRef.value.addEventListener('ended', () => {
      playingUrl.value = ''
    })
    audioRef.value.addEventListener('timeupdate', () => {
      audioCurrentTime.value = audioRef.value.currentTime;
      audioDuration.value = audioRef.value.duration || 0;
    })
    audioRef.value.addEventListener('loadedmetadata', () => {
      audioDuration.value = audioRef.value.duration || 0;
    })
    audioRef.value.volume = audioVolume.value;
  }
})

watch(audioVolume, (val) => {
  if (audioRef.value) audioRef.value.volume = val;
})
</script>

<style scoped>
.bg {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}
.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
  overflow: hidden;
  background: transparent;
}
.header {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  background: transparent;
  padding-top: 12px;
}
.header-content {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.voice-clone-card {
  width: 350px;
  background: v-bind('theme === "light" ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.3)"');
  box-shadow: 0 2px 8px v-bind('theme === "light" ? "rgba(0, 0, 0, 0.05)" : "rgba(0, 0, 0, 0.2)"');
  border-radius: 12px;
  margin-top: 4px;
  padding: 4px 18px 6px 18px;
  position: relative;
  border: 1px solid v-bind('theme === "light" ? "rgba(255, 255, 255, 0.2)" : "rgba(0, 0, 0, 0.4)"');
}
.voice-clone-flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.voice-clone-info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.voice-clone-title {
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 2px;
  margin-right: 0;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
}
.voice-clone-desc {
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.6)" : "#e0e0e0"') !important;
  font-size: 13px;
  margin-bottom: 0;
}
.clone-btn {
  border-radius: 20px;
  margin-left: 32px;
  background: v-bind('theme === "light" ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.3)"') !important;
  border: 1px solid v-bind('theme === "light" ? "rgba(255, 255, 255, 0.2)" : "rgba(0, 0, 0, 0.4)"') !important;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
}
.clone-btn:hover {
  background: v-bind('theme === "light" ? "rgba(255, 255, 255, 0.2)" : "rgba(0, 0, 0, 0.4)"') !important;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px v-bind('theme === "light" ? "rgba(0, 0, 0, 0.15)" : "rgba(0, 0, 0, 0.4)"') !important;
}
.main {
  flex: 1;
  background: transparent;
  margin-top: 10px;
  overflow-y: auto;
  overflow-x: hidden;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
  min-height: 0;
}

.main::-webkit-scrollbar {
  width: 6px;
}

.main::-webkit-scrollbar-thumb {
  background-color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.2)" : "rgba(255, 255, 255, 0.2)"');
  border-radius: 3px;
}

.main::-webkit-scrollbar-track {
  background-color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.05)" : "rgba(0, 0, 0, 0.05)"');
}

.voice-col {
  margin-bottom: 20px;
  width: 100%;
}
.voice-card {
  background: v-bind('theme === "light" ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.3)"');
  border-radius: 12px;
  min-height: 70px;
  display: flex;
  align-items: center;
  box-shadow: 0 2px 8px v-bind('theme === "light" ? "rgba(0, 0, 0, 0.05)" : "rgba(0, 0, 0, 0.2)"');
  width: 100%;
  border: 1px solid v-bind('theme === "light" ? "rgba(255, 255, 255, 0.2)" : "rgba(0, 0, 0, 0.4)"');
}
.voice-card-content {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 18px;
  font-weight: 500;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
}
.play-icon {
  font-size: 22px;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.6)" : "#bfcbd9"');
}
.drawer-content {
  font-size: 15px;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"');
}
.drawer-desc {
  font-size: 13px;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.6)" : "#e0e0e0"') !important;
  margin-top: 4px;
  margin-bottom: 4px;
  line-height: 1.7;
}
.container, .header, .main, h2, h3, .el-card, .el-drawer__body, .el-drawer__header {
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
}
.el-drawer__body,
.el-drawer__header,
.drawer-content,
.drawer-desc {
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
}
.el-drawer__title {
  font-weight: bold;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
}
.section-title {
  font-size: 20px;
  font-weight: bold;
  color: v-bind('theme === "light" ? "rgba(0, 0, 0, 0.8)" : "#fff"') !important;
  padding-bottom: 8px;
  border-bottom: 2px solid v-bind('theme === "light" ? "rgba(0, 0, 0, 0.2)" : "rgba(255, 255, 255, 0.2)"');
  margin-bottom: 16px;
}
</style>

